﻿using System;

namespace ESoft.Extensions
{
    public static class DateTimeExtensions
    {
        /// <summary>
        /// 获取当前时间的iso格式字符串
        /// </summary>
        /// <param name="dateTime">The date time.</param>
        /// <returns>System.String.</returns>
        public static string ToIsoString(this DateTime dateTime)
        {
            return dateTime.ToString("yyyy-MM-dd HH:mm:ss");
        }

        /// <summary>
        ///     转unix时间
        /// </summary>
        /// <param name="dateTime">The date time.</param>
        /// <returns>System.Int64.</returns>
        public static long ToUnixTime(this DateTime dateTime)
        {
               var startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1, 0, 0, 0, 0));
            return (long) Math.Round((dateTime - startTime).TotalMilliseconds, MidpointRounding.AwayFromZero);
        }

        /// <summary>
        /// 当前时间月份的第一天
        /// </summary>
        /// <param name="dateTime">The date time.</param>
        /// <returns>DateTime.</returns>
        public static DateTime FirstDayOfMonth(this DateTime dateTime)
        {
            return new DateTime(dateTime.AddMonths(-1).Year, dateTime.AddMonths(-1).Month, 1);
        }

        /// <summary>
        /// 当前时间月份的最后一天
        /// </summary>
        /// <param name="dateTime">The date time.</param>
        /// <returns>DateTime.</returns>
        public static DateTime LastDayOfMonth(this DateTime dateTime)
        {
            return dateTime.FirstDayOfMonth().AddMonths(1).AddDays(-1);
        }

        /// <summary>
        /// 当前时间月份天数
        /// </summary>
        /// <param name="dateTime">The date time.</param>
        /// <returns>System.Int32.</returns>
        public static int DaysInMonth(this DateTime dateTime)
        {
            return DateTime.DaysInMonth(dateTime.Year, dateTime.Month);
        }

        /// <summary>
        /// 月数差
        /// 当前时间减去date月数，例现在2017-11,date:2016-11返回值则为12
        /// </summary>
        /// <param name="now">The now.</param>
        /// <param name="date">The date.</param>
        /// <returns>System.Int32.</returns>
        public static int MonthDifference(this DateTime now, DateTime date)
        {
            return now.Month - date.Month + 12 * (now.Year - date.Year);
        }

        /// <summary>
        /// 天数差
        /// 当前时间减去date天数，例现在2017-11-3,date:2016-11-3返回值则为365
        /// </summary>
        /// <param name="now">The now.</param>
        /// <param name="date">The date.</param>
        /// <returns>System.Int32.</returns>
        public static int DayDifference(this DateTime now, DateTime date)
        {
            return (int) (now.Date - date.Date).TotalDays;
        }

        /// <summary>
        /// 年份差
        /// </summary>
        /// <param name="startDate">The start date.</param>
        /// <param name="endDate">The end date.</param>
        /// <returns>System.Int32.</returns>
        public static int YearDifference(this DateTime startDate, DateTime endDate)
        {
            var age = endDate.Year - startDate.Year;
            if (startDate > endDate.AddYears(-age))
                age--;

            return age;
        }

        /// <summary>
        /// 判断时间是否为同一天
        /// </summary>
        /// <param name="now">The now.</param>
        /// <param name="date">The date.</param>
        /// <returns><c>true</c> if [is day equals] [the specified date]; otherwise, <c>false</c>.</returns>
        public static bool IsDayEquals(this DateTime now, DateTime date)
        {
            return now.Date == date.Date;
        }

        /// <summary>
        ///判断时间用份是否相同
        /// </summary>
        /// <param name="now">The now.</param>
        /// <param name="date">The date.</param>
        /// <returns><c>true</c> if [is month equals] [the specified date]; otherwise, <c>false</c>.</returns>
        public static bool IsMonthEquals(this DateTime now, DateTime date)
        {
            return now.Year == date.Year && now.Month == date.Month;
        }

        /// <summary>
        /// 判断时间年份是否相同
        /// </summary>
        /// <param name="now">The now.</param>
        /// <param name="date">The date.</param>
        /// <returns><c>true</c> if [is year equals] [the specified date]; otherwise, <c>false</c>.</returns>
        public static bool IsYearEquals(this DateTime now, DateTime date)
        {
            return now.Year == date.Year;
        }

        /// <summary>
        /// 可空时间转格式为可空utc格式
        /// </summary>
        public static DateTime? ToUniversalTime(this DateTime? dateTime)
        {
            return dateTime?.ToUniversalTime();
        }

        /// <summary>
        ///     Converts a Coordinated Universal Time (UTC) to the time in a specified time zone.
        /// </summary>
        /// <param name="dateTime">The Coordinated Universal Time (UTC).</param>
        /// <param name="destinationTimeZone">The time zone to convert  to.</param>
        /// <returns>
        ///     The date and time in the destination time zone. Its  property is  if  is ; otherwise, its  property is .
        /// </returns>
        public static DateTime ConvertTimeFromUtc(this DateTime utcDateTime, TimeZoneInfo destinationTimeZone)
        {
            return TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, destinationTimeZone);
        }

        public static DateTime ConvertTimeFromUtc(this DateTime utcDateTime, string timeZoneId)
        {
            var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
            return ConvertTimeFromUtc(utcDateTime, timeZoneInfo);
        }

        /// <summary>
        ///     Converts a time to the time in a particular time zone.
        /// </summary>
        /// <param name="dateTime">The date and time to convert.</param>
        /// <param name="destinationTimeZone">The time zone to convert  to.</param>
        /// <returns>The date and time in the destination time zone.</returns>
        public static DateTime ConvertTime(this DateTime dateTime, TimeZoneInfo destinationTimeZone)
        {
            return TimeZoneInfo.ConvertTime(dateTime, destinationTimeZone);
        }

        /// <summary>
        ///     Converts a time from one time zone to another.
        /// </summary>
        /// <param name="dateTime">The date and time to convert.</param>
        /// <param name="sourceTimeZone">The time zone of .</param>
        /// <param name="destinationTimeZone">The time zone to convert  to.</param>
        /// <returns>
        ///     The date and time in the destination time zone that corresponds to the  parameter in the source time zone.
        /// </returns>
        public static DateTime ConvertTime(this DateTime dateTime, TimeZoneInfo sourceTimeZone, TimeZoneInfo destinationTimeZone)
        {
            return TimeZoneInfo.ConvertTime(dateTime, sourceTimeZone, destinationTimeZone);
        }

        /// <summary>
        /// 获取年龄
        /// </summary>
        /// <param name="this">The this.</param>
        /// <returns>System.Int32.</returns>
        public static int Age(this DateTime @this)
        {
            if (DateTime.Today.Month < @this.Month ||
                DateTime.Today.Month == @this.Month &&
                DateTime.Today.Day < @this.Day)
            {
                return DateTime.Today.Year - @this.Year - 1;
            }
            return DateTime.Today.Year - @this.Year;
        }
    }
}